package com.mdinic.blogovi.front.page.blogpost;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.PageCreator;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.pages.RedirectPage;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.request.resource.PackageResourceReference;
import org.apache.wicket.spring.injection.annot.SpringBean;

import com.mdinic.blogovi.front.common.AjaxLinkPerson;
import com.mdinic.blogovi.front.common.BDateTimeLabel;
import com.mdinic.blogovi.front.common.BlogTypePanel;
import com.mdinic.blogovi.front.common.SmallPersonPhoto;
import com.mdinic.blogovi.front.common.ThumbPhoto;
import com.mdinic.blogovi.front.page.BSession;
import com.mdinic.blogovi.front.page.person.PersonViewPage;
import com.mdinic.blogovi.model.BlogPost;
import com.mdinic.blogovi.model.Fav;
import com.mdinic.blogovi.model.Person;
import com.mdinic.blogovi.model.Share;
import com.mdinic.blogovi.model.Vote;
import com.mdinic.blogovi.service.BlogPostService;

public class BlogPostPanel extends Panel {

    public static enum BlogPostPanelType {
        LIST, SINGLE, FOLLOW
    };

    private static final int COMMENT_CUT_LEN = 80;

    private static final Logger LOG = Logger.getLogger(BlogPostPanel.class);

    public static final PackageResourceReference noFavStar = new PackageResourceReference(BlogPostPanel.class,
            "nofav.png"); // no fav
    public static final PackageResourceReference favStar = new PackageResourceReference(BlogPostPanel.class, "fav.png");

    public static final PackageResourceReference upArrow = new PackageResourceReference(BlogPostPanel.class, "up48.png");
    public static final PackageResourceReference downArrow = new PackageResourceReference(BlogPostPanel.class,
            "down48.png");

    public static final PackageResourceReference upArrowUnused = new PackageResourceReference(BlogPostPanel.class,
            "up48pale.png");
    public static final PackageResourceReference downArrowUnused = new PackageResourceReference(BlogPostPanel.class,
            "down48pale.png");

    public static final PackageResourceReference shareNo = new PackageResourceReference(BlogPostPanel.class,
            "share19p.png");

    public static final PackageResourceReference shareP = new PackageResourceReference(BlogPostPanel.class,
            "share19.png");

    public static final PackageResourceReference tweet = new PackageResourceReference(BlogPostPanel.class, "tweet.png");

    private static final String COMMENT_NR = "comment_nr";

    private static final String LIST = "list";

    private static final String ID = "panel";

    private static final long serialVersionUID = 1L;

    @SpringBean
    private BlogPostService blogPostService;

    public BlogPostPanel(List<BlogPost> posts, final BlogPostPanelType type) {
        super(ID);

        if (type.equals(BlogPostPanelType.LIST)) {
            add(new BlogTypePanel("filter"));
        }

        final List<Fav> favList;
        final List<Vote> voteList;
        final List<Share> shareList;
        if (BSession.get().isLoggedIn()) {
            favList = Fav.findFavsByPerson(BSession.get().getPerson()).getResultList();
            voteList = Vote.findVotesByPerson(BSession.get().getPerson()).getResultList();
            shareList = Share.findSharesByPerson(BSession.get().getPerson()).getResultList();
        } else {
            favList = new ArrayList<Fav>();
            voteList = new ArrayList<Vote>();
            shareList = new ArrayList<Share>();
        }

        ListView<BlogPost> list = new ListView<BlogPost>(LIST, posts) {

            private static final long serialVersionUID = 1L;

            @Override
            protected void populateItem(final ListItem<BlogPost> item) {

                final PageParameters parameters = new PageParameters();
                parameters.add(BlogPostViewPage.URL_PARAM_NAME, item.getModelObject().getId());

                Link<Void> thumbLink = new Link<Void>("thumb_link") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick() {
                        markRead(type, item);
                        setResponsePage(BlogPostViewPage.class, parameters);
                    };
                };

                thumbLink.add(new ThumbPhoto("thumb", item.getModelObject()));

                thumbLink.setEnabled(!type.equals(BlogPostPanelType.SINGLE));
                item.add(thumbLink);

                Vote tempVoted = null;
                for (Vote vote : voteList) {
                    if (vote.getPost().getId().equals(item.getModelObject().getId())) {
                        tempVoted = vote;
                        break;
                    }
                }
                final IModel<Vote> voted = new Model<Vote>(tempVoted);

                final Label labelUp = new Label("vote_up_nr", new PropertyModel<Integer>(item.getModel(), "voteUp"));
                labelUp.setOutputMarkupId(true);
                final Label labelDown = new Label("vote_down_nr", new PropertyModel<Integer>(item.getModel(),
                        "voteDown"));
                labelDown.setOutputMarkupId(true);

                AjaxLinkPerson voteDownLink;
                AjaxLinkPerson voteUpLink;

                // vote

                final Image upImage = new Image("up_arrow", new Model<PackageResourceReference>() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public PackageResourceReference getObject() {
                        if (voted.getObject() == null) {
                            return upArrowUnused;
                        } else {
                            if (voted.getObject().getUp()) {
                                return upArrow;
                            } else {
                                return upArrowUnused;
                            }
                        }
                    }
                });

                final Image downImage = new Image("down_arrow", new Model<PackageResourceReference>() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public PackageResourceReference getObject() {
                        if (voted.getObject() == null) {
                            return downArrowUnused;
                        } else {
                            if (voted.getObject().getUp()) {
                                return downArrowUnused;
                            } else {
                                return downArrow;
                            }
                        }
                    }
                });

                voteUpLink = new AjaxLinkPerson("vote_up_link") {

                    private static final long serialVersionUID = 2654894277874008936L;

                    @Override
                    public void click(AjaxRequestTarget target) {
                        BlogPost post = blogPostService.vote(BSession.get().getPerson(), item.getModelObject(), true);

                        item.setModelObject(post);

                        if (voted.getObject() == null) {
                            voted.setObject(new Vote(BSession.get().getPerson(), item.getModelObject(), true));
                        } else {
                            voted.getObject().setUp(true);
                        }

                        target.add(labelUp, labelDown, upImage, downImage);
                    }

                };

                voteDownLink = new AjaxLinkPerson("vote_down_link") {

                    private static final long serialVersionUID = -1224252870734643190L;

                    @Override
                    public void click(AjaxRequestTarget target) {
                        BlogPost post = blogPostService.vote(BSession.get().getPerson(), item.getModelObject(), false);
                        item.setModelObject(post);

                        if (voted.getObject() == null) {
                            voted.setObject(new Vote(BSession.get().getPerson(), item.getModelObject(), false));
                        } else {
                            voted.getObject().setUp(false);
                        }
                        target.add(labelUp, labelDown, upImage, downImage);
                    }

                };

                item.add(labelUp);
                item.add(labelDown);

                downImage.setOutputMarkupId(true);
                upImage.setOutputMarkupId(true);

                voteUpLink.add(upImage);
                voteDownLink.add(downImage);

                // end vote
                // fav

                PackageResourceReference defShare = shareNo;

                for (Share share : shareList) {
                    if (share.getBlogPost().getId().equals(item.getModelObject().getId())) {
                        defShare = shareP;
                        break;
                    }
                }

                final Image shareImage = new Image("share_img", defShare);
                shareImage.setOutputMarkupId(true);

                AjaxLinkPerson shareLink = new AjaxLinkPerson("share_link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void click(AjaxRequestTarget target) {
                        Boolean share = blogPostService.share(BSession.get().getPerson(), item.getModelObject());
                        if (share) {
                            shareImage.setImageResourceReference(shareP);
                        } else {
                            shareImage.setImageResourceReference(shareNo);
                        }
                        target.add(shareImage);
                    }

                };

                PackageResourceReference star = noFavStar;
                for (Fav fav : favList) {
                    if (fav.getPost().getId().equals(item.getModelObject().getId())) {
                        star = favStar;
                        break;
                    }
                }

                final Image image = new Image("fav_img", star);
                image.setOutputMarkupId(true);

                AjaxLinkPerson favLink = new AjaxLinkPerson("fav_link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void click(AjaxRequestTarget target) {
                        Boolean fav = blogPostService.fav(BSession.get().getPerson(), item.getModelObject());
                        if (fav) {
                            image.setImageResourceReference(favStar);
                        } else {
                            image.setImageResourceReference(noFavStar);
                        }
                        target.add(image);
                    }

                };

                PageParameters pageParameters = new PageParameters();
                pageParameters.add(BlogPostViewPage.URL_PARAM_NAME, item.getModelObject().getId());

                String msg = item.getModelObject().getHeadline()
                        + " "
                        + RequestCycle.get().getUrlRenderer()
                                .renderFullUrl(Url.parse(urlFor(BlogPostViewPage.class, pageParameters).toString()));

                String tweetLinkValue = StringUtils.EMPTY;
                try {
                    tweetLinkValue = URLEncoder.encode(msg, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    LOG.error("error while generating twit link", e);
                }
                ExternalLink tweetLink = new ExternalLink("tweet_link", "http://twitter.com/home?status="
                        + tweetLinkValue);

                item.add(tweetLink);

                final Image tweetImage = new Image("tweet_img", tweet);

                tweetLink.add(tweetImage);

                // comment

                Link<Void> commentLink = new Link<Void>("comment_link") {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick() {
                        setResponsePage(BlogPostViewPage.class, parameters);
                        markRead(type, item);
                    }
                };
                commentLink.add(new Label(COMMENT_NR, item.getModelObject().getComment()));

                item.add(commentLink);
                commentLink.setVisible(!type.equals(BlogPostPanelType.SINGLE));

                item.add(voteUpLink);
                item.add(voteDownLink);

                favLink.add(image);
                item.add(favLink);

                shareLink.add(shareImage);
                item.add(shareLink);

                boolean moreLinkVisibe = false;
                if (type.equals(BlogPostPanelType.SINGLE)
                        || item.getModelObject().getDescription().length() < COMMENT_CUT_LEN) {
                    item.add(new Label(BlogPost.DESCRIPTION, item.getModelObject().getDescription()));
                } else {
                    item.add(new Label(BlogPost.DESCRIPTION, item.getModelObject().getDescription()
                            .substring(0, COMMENT_CUT_LEN)));
                    moreLinkVisibe = true;
                }

                item.add(new BookmarkablePageLink<BlogPostViewPage>("more_link", BlogPostViewPage.class, parameters)
                        .setVisible(moreLinkVisibe));

                PageParameters userParameters = new PageParameters();
                userParameters.add(BlogPostViewPage.URL_PARAM_NAME, item.getModelObject().getPerson().getId());
                BookmarkablePageLink<PersonViewPage> personLink = new BookmarkablePageLink<PersonViewPage>("user_link",
                        PersonViewPage.class, userParameters);
                personLink
                        .add(new Label(Person.NICKNAME, new PropertyModel<String>(item.getModel(), "person.nickname")));
                item.add(personLink);

                item.add(new SmallPersonPhoto("avatar", item.getModelObject().getPerson()));

                ExternalLink headlineLine = new ExternalLink("headline_link", item.getModelObject().getUrl());

                final PageCreator pc = new PageCreator() {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public Page createPage() {
                        return new RedirectPage(item.getModelObject().getUrl());
                    }
                };

                headlineLine.add(new AjaxEventBehavior("onclick") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    protected void onEvent(AjaxRequestTarget target) {
                        item.getModelObject().incClick();
                        setResponsePage(pc.createPage());
                        markRead(type, item);
                        // String javascript = "var win=window.open('" +
                        // item.getModelObject().getUrl()
                        // + "', '_blank');win.focus();";
                        // target.appendJavaScript(javascript);
                    }

                });
                headlineLine.add(new AttributeModifier("href", item.getModelObject().getUrl()));

                headlineLine.add(new Label(BlogPost.HEADLINE, item.getModelObject().getHeadline()));
                item.add(headlineLine);

                item.add(new Label(BlogPost.CLICK, item.getModelObject().getClick()));
                item.add(new Label(BlogPost.VIEW, item.getModelObject().getView()));

                item.add(new BDateTimeLabel(BlogPost.POSTED, item.getModelObject().getPosted()));

                Link<Void> blogLink = new Link<Void>("blog_link") {

                    private static final long serialVersionUID = 1L;

                    @Override
                    public void onClick() {
                        PageParameters pageParameters = new PageParameters();
                        pageParameters.add(BlogPostListByBlogPage.URL_PARAM_NAME, item.getModelObject().getBlog()
                                .getId());
                        setResponsePage(BlogPostListByBlogPage.class, pageParameters);
                    }
                };

                blogLink.add(new Label("blogUrl", new PropertyModel<String>(item.getModel(), "blog.url")));
                item.add(blogLink);
            }
        };

        add(list);
    }

    private void markRead(final BlogPostPanelType type, final ListItem<BlogPost> item) {
        if (type.equals(BlogPostPanelType.FOLLOW) && !BSession.get().isFollowFilterRead()) {
            blogPostService.markRead(BSession.get().getPerson(), item.getModelObject());
        }
    }
}
